 /**************************************************************************//**
 * @file    array_helper.c
 * @author  İsmail SEZEN (email: sezenismail@gmail.com)
 * @date    06.02.2011
 *
 * <b>Description</b>
 *
 * This file contains helper functions about array manipulatons.\n
 *
 * Copyright (C) 2010 İsmail SEZEN
 *
 * <b>License</b>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *****************************************************************************/

/* Include Drectives *///{
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <array_helper.h>
#include <logger.h>
//}

/*! \brief A small Error macro prints the error to standart output  and exits the program */
#define ERROR(e) {fprintf(stderr,"Error: %s\n", e);exit(EXIT_FAILURE);}

/*! @name Public
 *  These functions are defined in the header file array_helper.h
 */
//@{//{

/*! @brief Allocates enough memory as \a size. *
 *  @param[in] size Allocation size
 *  @return void
 *  @warning Don't forget to release the allocated memory after allocation. */
void* xmalloc (size_t size) {
	register void* value = malloc(size);
	if (value == 0) ERROR("Fatal: Virtual memory exhausted");
	return value;
}

/*! @brief Reallocates enough memory as \a size on the \a arr pointer.
 *  @param[in] arr Pointer of array
 *  @param[in] size Allocation size
 *  @return void
 *  @warning Don't forget to release the allocated memory after allocation. */
void* xrealloc(void* arr, size_t size) {
	register void *value =  realloc(arr, size);
	if (value == 0) ERROR("Fatal: Virtual memory exhausted");
	return value;
}

/*! @brief Allocates enough memory for a 3D short array has dimensions \a N1 , \a N2 , \a N3.
 *  @param[in] N1 First Dimension Size
 *  @param[in] N2 Second Dimension Size
 *  @param[in] N3 Third Dimension Size
 *  @return Returns the created 3D array.
 *  @warning Don't forget to free the array after creation. */
short*** arr_3d_short(int N1, int N2, int N3) {
	short*** dim1 = arr_malloc(short**,N1);/* Allocate enough memory for First Dimension */
	short** dim2 = arr_malloc(short*,N2*N1);/* Allocate enough memory for Second Dimension */
	short* dim3 = arr_malloc(short,N1 * N2 * N3);/* Allocate enough memory for Third Dimension */
	//
	short*** data = dim1;/* Hold the start address of the array to return end of the function */
	short*** p_last_dim1 = dim1 + N1;/* Last address of the dimension #1 */
	//
	do{
		(*dim1++) = dim2;/* appoint dim2 pointer to dim1 and shift dim1 forward */
		short** p_last_dim2 = dim2 + N2;/* Last address of the dimension #2 */
		do{
			(*dim2++) = (dim3 +=N3);/* shift dim3 pointer up to N3 and appoint to dim2 pointer */
		}while(dim2<p_last_dim2);
	}while(dim1<p_last_dim1);
	return data; // Success
}

/*! @brief Allocates enough memory for a 2D char array has dimensions \a N1 , \a N2.
 *  @param[in] N1 First Dimension Size
 *  @param[in] N2 Second Dimension Size
 *  @return Returns a pointer to 2D char array
 *  @warning Don't forget to free the array after creation. */
char*** arr_2d_char2p( int N1, int N2) {
	char*** dim1 = arr_malloc(char**,N1);
	char** dim2 = arr_malloc(char*,N1*N2);
	char*** data = dim1;
	char*** p_last_dim1 = dim1 + N1;
	//
	do{(*dim1++) = (dim2 +=N2);}while(dim1<p_last_dim1);
	return data; // Success
}

/*! @brief Allocates enough memory for a 2D char array has dimensions \a N1 , \a N2.
 *  @param[in] N1 First Dimension Size
 *  @param[in] N2 Second Dimension Size
 *  @return Returns a pointer to 2D char array if the operation is succeed otherwise returns NULL (0).
 *  @warning Don't forget to free the array after creation. */
char** arr_2d_char( int N1, int N2) {
	char** dim1 = arr_malloc(char*,N1);
	char*  dim2 = arr_malloc(char,N2*N1);
	char** data = dim1;
	char** p_last_dim1 = dim1 + N1;/* Last address of the dimension #1 */
	/* shift dim2 pointer up to N2 and appoint to dim1 pointer and shift dim1 until p_last_dim1 */
	do{(*dim1++) = (dim2 +=N2);}while(dim1<p_last_dim1);
	return data; // Success
}

/*! @brief Allocates enough memory for a 3D char array has dimensions \a N1 , \a N2 , \a N3.
 *  @param[in] N1 First Dimension Size
 *  @param[in] N2 Second Dimension Size
 *  @param[in] N3 Third Dimension Size
 *  @return Returns a pointer to 3D char array if the operation is succeed otherwise returns NULL (0).
 *  @warning Don't forget to free the array after creation. */
char*** arr_3d_char(int N1, int N2, int N3) {
	char*** dim1 = arr_malloc(char**,N1);/* Allocate enough memory for First Dimension */
	char** dim2 = arr_malloc(char*,N2*N1);/* Allocate enough memory for Second Dimension */
	char* dim3 = arr_malloc(char,N1 * N2 * N3);/* Allocate enough memory for Third Dimension */
	//
	char*** data = dim1;/* Hold the start address of the array to return end of the function */
	char*** p_last_dim1 = dim1 + N1;/* Last address of the dimension #1 */
	//
	do{
		(*dim1++) = dim2;/* appoint dim2 pointer to dim1 and shift dim1 forward */
		char** p_last_dim2 = dim2 + N2;/* Last address of the dimension #2 */
		do{
			(*dim2++) = (dim3 +=N3);/* shift dim3 pointer up to N3 and appoint to dim2 pointer */
		}while(dim2<p_last_dim2);
	}while(dim1<p_last_dim1);
	return data; // Success
}

//}//@}
